home *** CD-ROM | disk | FTP | other *** search
/ IRIX 6.2 Applications 1996 May / SGI IRIX 6.2 Applications 1996 May.iso / dist / impr_dev.idb / usr / impressario / src / libspool / SLUtil.c.z / SLUtil.c
C/C++ Source or Header  |  1996-05-06  |  20KB  |  744 lines

  1. /**************************************************************************
  2.  *                                      *
  3.  *           Copyright (c)    1991 Silicon Graphics, Inc.          *
  4.  *            All Rights Reserved                    *
  5.  *                                      *
  6.  *       THIS    IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SGI          *
  7.  *                                      *
  8.  * The copyright notice above does not evidence any actual of intended      *
  9.  * publication of such source code, and is an unpublished work by Silicon *
  10.  * Graphics, Inc. This material contains CONFIDENTIAL INFORMATION that is *
  11.  * the property of Silicon Graphics, Inc. Any use, duplication or      *
  12.  * disclosure not specifically authorized by Silicon Graphics is strictly *
  13.  * prohibited.                                  *
  14.  *                                      *
  15.  * RESTRICTED RIGHTS LEGEND:                          *
  16.  *                                      *
  17.  * Use, duplication or disclosure by the Government is subject to      *
  18.  * restrictions as set forth in subdivision (c)(1)(ii) of the Rights in      *
  19.  * Technical Data and Computer Software clause at DFARS 52.227-7013,      *
  20.  * and/or in similar or successor clauses in the FAR, DOD or NASA FAR      *
  21.  * Supplement. Unpublished - rights reserved under the Copyright Laws of  *
  22.  * the United States. Contractor is SILICON GRAPHICS, INC., 2011 N.      *
  23.  * Shoreline Blvd., Mountain View, CA 94039-7311              *
  24.  **************************************************************************
  25.  *
  26.  * File: SLUtil.c
  27.  *
  28.  * Description: This file contains misc. utility functions grlobally
  29.  *    available to internal SL routines.
  30.  *
  31.  **************************************************************************/
  32.  
  33.  
  34. #ident "$Revision: 1.11 $"
  35.  
  36.  
  37. #include <stdio.h>
  38. #include <string.h>
  39. #include <unistd.h>
  40. #include <stdlib.h>
  41. #include <fcntl.h>
  42. #include <errno.h>
  43. #ifdef sgi
  44. #include <bstring.h>
  45. #endif
  46. #include <sys/types.h>
  47. #include <sys/wait.h>
  48. #include <sys/time.h>
  49. #include <signal.h>
  50. #include <ctype.h>
  51. #include "spoolI.h"
  52.  
  53.  
  54. /* SLExec spooler output buffer globals */
  55.  
  56. char **_SLspooler_out_buf;            /* Output buffer text */
  57. int _SLspooler_nout;                /* # lines in output buffer */
  58. int _SLspooler_exit;                /* Spooler exit status */
  59.  
  60.  
  61. /* External functions needing declarations */
  62.  
  63. extern int select(int, fd_set*, fd_set*, fd_set*, struct timeval*);
  64.  
  65.  
  66. /* Local functions */
  67.  
  68. static void spooler_buf_init(void);
  69. static void spooler_buf_add(char*);
  70. static int read_ready(int, int);
  71.  
  72.  
  73. /**************************************************************************
  74.  *
  75.  * Function: _SLIsEmpty
  76.  *
  77.  * Description: Determines if a string is empty or filled only with
  78.  *      whitespace.
  79.  *
  80.  * Parameters:
  81.  *      str (I) - string to test
  82.  *
  83.  * Return: 0 not empty. 1 if string is empty.
  84.  *
  85.  **************************************************************************/
  86.  
  87. int _SLIsEmpty(register const char *str)
  88. {
  89.     if (str == NULL)
  90.         return 1;
  91.     for (; *str; str++)
  92.         if (!isspace((int)*str))
  93.             return 0;
  94.     return 1;
  95. }
  96.  
  97.  
  98. /**************************************************************************
  99.  *
  100.  * Function: _SLSkipSpace
  101.  *
  102.  * Description: Skips whitespace and returns a pointer to the first
  103.  *    non-whitespace character or NULL if there is only whitespace
  104.  *    on the line.
  105.  *
  106.  * Parameters: 
  107.  *    sbuf (I) - string buffer to parse for whitespace.
  108.  *
  109.  * Return: Pointer to first non-whitespace character or NULL if the
  110.  *    line consists only of whitespace characters;
  111.  *
  112.  **************************************************************************/
  113.  
  114. char *_SLSkipSpace(char *sbuf)
  115. {
  116.     char *sptr = NULL;
  117.  
  118.     while (*sbuf) {
  119.     if (!isspace(*sbuf)) {
  120.         sptr = sbuf;
  121.         break;
  122.     }
  123.     sbuf++;
  124.     }
  125.  
  126.     return sptr;
  127. }
  128.  
  129.  
  130. /**************************************************************************
  131.  *
  132.  * Function: _SLInitPlist
  133.  *
  134.  * Description: Initializes a printer list.
  135.  *
  136.  * Parameters: 
  137.  *    plistp (O) - pointer to printer list.
  138.  *    nump (O) - pointer to number of printers on list.
  139.  *
  140.  * Return: none
  141.  *
  142.  **************************************************************************/
  143.  
  144. void _SLInitPlist(SLPrinterStruct **plistp, int *nump)
  145. {
  146.     register int i;
  147.     register SLPrinterStruct *ptr;
  148.  
  149.     if (*plistp) {
  150.     /*
  151.      * Free the storage for each printer. If this becomes a
  152.      * performance problem we can go to free-lists.
  153.      */
  154.     for (i = 0, ptr = *plistp; i < *nump; i++, ptr++)
  155.         _SLInitPentry(ptr);
  156.  
  157.     /*
  158.      * Free the list storage
  159.      */
  160.     free((char*)*plistp);
  161.     *plistp = NULL;
  162.     }
  163.     *nump = 0;
  164. }
  165.  
  166.  
  167. /**************************************************************************
  168.  *
  169.  * Function: _SLInitPentry
  170.  *
  171.  * Description: Initializes a printer info entry. All storage alocated int
  172.  *    the SLPrinterStruct is freed.
  173.  *
  174.  * Parameters: 
  175.  *    pentry (O) - pointer to printer info structure.
  176.  *
  177.  * Return: none
  178.  *
  179.  **************************************************************************/
  180.  
  181. void _SLInitPentry(SLPrinterStruct *pentry)
  182. {
  183.     if (pentry) {
  184.         if (pentry->local_name) {
  185.         free((char*)pentry->local_name);
  186.         pentry->local_name = NULL;
  187.     }
  188.     if (pentry->formal_name) {
  189.         free((char*)pentry->formal_name);
  190.         pentry->formal_name = NULL;
  191.     }
  192.     if (pentry->type) {
  193.         free((char*)pentry->type);
  194.         pentry->type = NULL;
  195.     }
  196.     if (pentry->dev) {
  197.         free((char*)pentry->dev);
  198.         pentry->dev = NULL;
  199.     }
  200.     if (pentry->remote_host) {
  201.         free((char*)pentry->remote_host);
  202.         pentry->remote_host = NULL;
  203.     }
  204.     if (pentry->remote_name) {
  205.         free((char*)pentry->remote_name);
  206.         pentry->remote_name = NULL;
  207.     }
  208.     if (pentry->network_type) {
  209.         free(pentry->network_type);
  210.         pentry->network_type = NULL;
  211.     }
  212.     }
  213. }
  214.  
  215.  
  216. /**************************************************************************
  217.  *
  218.  * Function: _SLAddPrinter
  219.  *
  220.  * Description: Adds a printer to the specified printer list
  221.  *
  222.  * Parameters: 
  223.  *    pinfo (I) - pointer to the printer info struct to add to the list
  224.  *    plistp (O) - pointer to printer list.
  225.  *    nump (O) - pointer to number of printers on list.
  226.  *
  227.  * Return: None
  228.  *
  229.  **************************************************************************/
  230.  
  231. void _SLAddPrinter(const SLPrinterStruct *pinfo, SLPrinterStruct **plistp,
  232.                 int *nump)
  233. {
  234.     (*nump)++;
  235.     if (*plistp)
  236.     /*
  237.      * We realloc for each printer we add. Can realloc in chunks
  238.      * if this is a performance problem.
  239.     */
  240.     *plistp = (SLPrinterStruct*)realloc(*plistp,
  241.                 (*nump) * sizeof(SLPrinterStruct));
  242.     else
  243.     *plistp = (SLPrinterStruct*)malloc((*nump) * sizeof(SLPrinterStruct));
  244.     (*plistp)[*nump - 1] = *pinfo;
  245. }
  246.  
  247.  
  248. /**************************************************************************
  249.  *
  250.  * Function: _SLInitQueue
  251.  *
  252.  * Description: Initializes a printer queue.
  253.  *
  254.  * Parameters: 
  255.  *    queuep (O) - pointer to queue.
  256.  *    nump (O) - pointer to number of jobs in queue.
  257.  *
  258.  * Return: none
  259.  *
  260.  **************************************************************************/
  261.  
  262. void _SLInitQueue(SLQueueStruct **queuep, int *nump)
  263. {
  264.     int i;
  265.     SLQueueStruct *qptr;
  266.  
  267.     if (*queuep) {
  268.     /*
  269.      * Free the storage for each job. If this becomes a
  270.      * performance problem we can go to free-lists.
  271.      */
  272.     for (i = 0, qptr = *queuep; i < *nump; i++, qptr++)
  273.         _SLFreeQueueEntry(qptr);
  274.  
  275.     /*
  276.      * Free the list storage
  277.      */
  278.     free((char*)*queuep);
  279.     *queuep = NULL;
  280.     }
  281.     *nump = 0;
  282. }
  283.  
  284.  
  285. /**************************************************************************
  286.  *
  287.  * Function: _SLFreeQueueEntry
  288.  *
  289.  * Description: Frees the storage for a single queue entry
  290.  *
  291.  * Parameters: 
  292.  *    entry (I) - pointer to the entry whose storage is to be freed
  293.  *
  294.  * Return: none
  295.  *
  296.  **************************************************************************/
  297.  
  298. void _SLFreeQueueEntry(SLQueueStruct *entry)
  299. {
  300.     if (entry->job_id)
  301.     free((char*)entry->job_id);
  302.     if (entry->username)
  303.     free((char*)entry->username);
  304.     if (entry->title)
  305.     free(entry->title);
  306. }
  307.  
  308.  
  309. /**************************************************************************
  310.  *
  311.  * Function: _SLAddQueue
  312.  *
  313.  * Description: Adds a job to the specified queue
  314.  *
  315.  * Parameters: 
  316.  *    queuep (O) - pointer to queue
  317.  *    nump (O) - pointer to number of jobs in queue.
  318.  *
  319.  * Return: Pointer to newly added queue structure.
  320.  *
  321.  **************************************************************************/
  322.  
  323. SLQueueStruct* _SLAddQueue(SLQueueStruct **queuep, int *nump)
  324. {
  325.     (*nump)++;
  326.     if (*queuep)
  327.     /*
  328.      * We realloc for each job we add. Can realloc in chunks
  329.      * if this is a performance problem.
  330.     */
  331.     *queuep = (SLQueueStruct*)realloc(*queuep,
  332.                 (*nump) * sizeof(SLQueueStruct));
  333.     else
  334.     *queuep = (SLQueueStruct*)malloc((*nump) * sizeof(SLQueueStruct));
  335.     return &(*queuep)[*nump - 1];
  336. }
  337.  
  338.  
  339. /**************************************************************************
  340.  *
  341.  * Function: _SLExec
  342.  *
  343.  * Description: Executes the specified command and returns the exit
  344.  *    status. The command output and the number of lines of output
  345.  *    are stored in globals for use in error reporting and ID
  346.  *    parsing.
  347.  *
  348.  * Parameters: 
  349.  *    job_source (I) - specifies the source of a print job. This is
  350.  *        specified for print job submittal. Otherwise it may be
  351.  *        set to NULL.
  352.  *    cmd (I) - command to execute
  353.  *    timeout_flag (I) - TRUE == use select with a timeout; FALSE ==
  354.  *               do not use select (i.e. no timeouts).
  355.  *    timeout_resp (O) - Timeout result. TRUE if timed out, FALSE if
  356.  *               did not timeout. Pointer can be NULL if 
  357.  *               timeout_flag is not TRUE.
  358.  *
  359.  * Return: Exit status of the specified command.
  360.  *
  361.  **************************************************************************/
  362.  
  363. int _SLExec(SLJobSourceUnion *job_source, char *cmd, int timeout_flag,
  364.                 int *timeout_resp)
  365. {
  366.     char buf[SL_BUFSIZ];
  367.     FILE *pptr;
  368.     int status;
  369.     int ret, ready_ret, pid, read_pipe[2];
  370.     int write_pipe[2];
  371.     int infd;
  372.     struct sigaction sact, orig_sact;
  373.     sigset_t sig_mask;
  374.  
  375.     /*
  376.      * First free the old output buffer if any
  377.      */
  378.     spooler_buf_init();
  379.  
  380.     /*
  381.      * Initialize the write pipe
  382.      */
  383.     write_pipe[0] = write_pipe[1] = 0;
  384.  
  385.     /*
  386.      * Initialize the input file descriptor.  If this is non-zero in
  387.      * the child process, we'll dup it to standard input.
  388.      */
  389.     infd = 0;
  390.  
  391.     /*
  392.      * If appropriate specify a file descriptor for the command to read
  393.      * from on its standard input.
  394.      *
  395.      * If a file descriptor is specified simply tell the command to read
  396.      * from that descriptor.
  397.      *
  398.      * If a buffer has been specified we will open a pipe and specify
  399.      * the pipe's read end as the file descriptor for the command to
  400.      * read as its stdin. We will write the buffer to the write end of
  401.      * the pipe.
  402.      */
  403.     (void)strcpy(buf, cmd);
  404.     if (job_source) {
  405.         switch(job_source->type) {
  406.         case SL_JOB_FILENAME:
  407.             if (SLdebug)
  408.             (void)fprintf(stderr,
  409.                 gettxt(_SGI_LIBSPOOL_DEBUG_FILENAME_JOB,
  410.                 "libspool Debug: _SLExec filename job\n"));
  411.         break;
  412.         case SL_JOB_FD:
  413.             if (SLdebug)
  414.            (void)fprintf(stderr, 
  415.                 gettxt(_SGI_LIBSPOOL_DEBUG_FD_JOB,
  416.                 "libspool Debug: _SLExec fd job\n"));
  417.         infd = job_source->fd_job.file_desc;
  418.         break;
  419.         case SL_JOB_BUF:
  420.             if (SLdebug)
  421.             (void)fprintf(stderr,
  422.                 gettxt(_SGI_LIBSPOOL_DEBUG_BUF_JOB,
  423.                 "libspool Debug: _SLExec buffer job\n"));
  424.         if (pipe(write_pipe) < 0) {
  425.             (void)fprintf(stderr, gettxt(_SGI_LIBSPOOL_PIPE_FAILED,
  426.           "libspool INTERNAL ERROR: _SLExec pipe failed (errno=%d)\n"),
  427.             errno);
  428.             return SL_ERROR;
  429.         }
  430.         infd = write_pipe[0];
  431.         break;
  432.         default:
  433.         break;
  434.     }
  435.     }
  436.  
  437.     /*
  438.      * Print some debug info if requested
  439.      */
  440.     if (SLdebug)
  441.     (void)fprintf(stderr, gettxt(_SGI_LIBSPOOL_DEBUG_EXECCMD,
  442.             "libspool Debug: _SLExec command \"%s\"\n"), cmd);
  443.  
  444.     /*
  445.      * Before we execute the command we need to default SIGCLD so that
  446.      * when the command terminates we don not call a user's SIGCLD
  447.      * handler. Do not worry about losing SIGCLD for the user because
  448.      * if we get one during our ignore period, the user's child will
  449.      * zombie and sigaction will raise a new SIGCLD if it detects a
  450.      * zombie when we reinstall the original handler.
  451.      */
  452.     sigemptyset(&sig_mask);
  453.     sact.sa_handler = SIG_DFL;
  454.     sact.sa_mask = sig_mask;
  455.     sact.sa_flags = 0;
  456.     (void)sigaction(SIGCLD, &sact, &orig_sact);
  457.  
  458.     /*
  459.      * Execute the command (adapted from popen)
  460.      *
  461.      * We fork a shell that executes the speicified command. The standard
  462.      * out of the command has been connected to the write end of a pipe
  463.      * that our parent process reads. For convenience we fdopen a stream
  464.      * based on the read end of the pipe.
  465.      */
  466.     if (pipe(read_pipe) < 0) {
  467.         (void)sigaction(SIGCLD, &orig_sact, NULL);
  468.     (void)fprintf(stderr, gettxt(_SGI_LIBSPOOL_PIPE_FAILED,
  469.         "libspool INTERNAL ERROR: _SLExec pipe failed (errno=%d)\n"),
  470.         errno);
  471.     return SL_ERROR;
  472.     }
  473.     if ((pid = fork()) == 0) {
  474.     /*
  475.      * Make child a process group leader so that if we timeout
  476.      * we can kill the child's pgroup and have all its children killed.
  477.      * This is especially important when dealing with rsh since it is
  478.      * flakey.
  479.      */
  480.     (void)setpgrp();
  481.  
  482.     /*
  483.      * Set up the pipes that the child will use to communicate with
  484.      * the parent.
  485.      */
  486.     if (infd) {
  487.         (void)dup2(infd, 0);
  488.         (void)close(infd);
  489.     }
  490.     if (write_pipe[1])            /* If writing to command */
  491.         (void)close(write_pipe[1]);        /*    close child write end */
  492.     (void)close(read_pipe[0]);        /* Close child read end */
  493.     if (read_pipe[1] != 1) {        /* If pipe not already stdout */
  494.         (void)close(1);            /* Close child stdout */
  495.         (void)fcntl(read_pipe[1], F_DUPFD, 1);    /* Make pipe chld out */
  496.         (void)close(read_pipe[1]);        /* Close our pipe write */
  497.     }
  498.  
  499.     /*
  500.      * Set up the environment so that we get output in the
  501.      * language we can parse and in the error message format
  502.      * we require.
  503.      */
  504.     putenv(SL_LANG);
  505.     putenv(SL_MSGFORMAT);
  506.  
  507.     /*
  508.      * Execute the child command
  509.      */
  510.     (void)execl(SL_CMD_SH, SL_CMD_SH_NAME, SL_CMD_SH_FLAG, buf, NULL);
  511.     exit(1);
  512.     }
  513.     if (pid == -1) {
  514.         (void)sigaction(SIGCLD, &orig_sact, NULL);
  515.     (void)fprintf(stderr, gettxt(_SGI_LIBSPOOL_FORK_FAILED,
  516.         "libspool INTERNAL ERROR: _SLExec fork failed (errno=%d)\n"),
  517.         errno);
  518.     return SL_ERROR;
  519.     }
  520.  
  521.     /*
  522.      * Set up the pipes that will be used to communicate with
  523.      * the child
  524.      */
  525.     if (write_pipe[0])            /* If writing to command */
  526.     (void)close(write_pipe[0]);    /*    close parent read end */
  527.     (void)close(read_pipe[1]);        /* Close parent write end */
  528.                     /* Create a stream for the pipe */
  529.     if ((pptr = fdopen(read_pipe[0], "r")) == NULL) {
  530.     (void)fprintf(stderr, gettxt(_SGI_LIBSPOOL_FDOPEN_FAILED,
  531.             "libspool INTERNAL ERROR: fdopen failed\n"));
  532.     return SL_ERROR;
  533.     }
  534.  
  535.     /*
  536.      * If the command is to be fed from a buffer, feed it
  537.      */
  538.     if (write_pipe[1]) {
  539.     (void)write(write_pipe[1], job_source->buf_job.buffer,
  540.                     job_source->buf_job.amount);
  541.     (void)close(write_pipe[1]);
  542.     }
  543.  
  544.     /*
  545.      * Read the output from the command and build the output buffer
  546.      */
  547.     while ((ready_ret = read_ready(read_pipe[0], timeout_flag)) != 0) {
  548.         if (fgets(buf, SL_SML_BUFSIZ, pptr) == NULL)
  549.         break;
  550.     buf[strlen(buf)-1] = '\0';
  551.     spooler_buf_add(buf);
  552.     }
  553.  
  554.     /*
  555.      * Close our end of the pipe to the child
  556.      */
  557.     (void)fclose(pptr);
  558.  
  559.     /*
  560.      * If the we have a timeout condition, explicitly kill the
  561.      * child's process group and set the timeout response
  562.      * (if not NULL pointer). The child is a process group leader
  563.      * and killing its group kills any children that may have been
  564.      * forked.
  565.      */
  566.     if (ready_ret == 0) {
  567.         if (SLdebug)
  568.         (void)fprintf(stderr, gettxt(_SGI_LIBSPOOL_DEBUG_TIMEOUT,
  569.         "libspool Debug: _SLExec timeout - killing pid %d\n"), pid);
  570.         (void)kill(-pid, SIGKILL);
  571.     }
  572.     if (timeout_resp)
  573.         *timeout_resp = (ready_ret) ? SL_FALSE: SL_TRUE;
  574.  
  575.     /*
  576.      * Wait for the child process executing the command to finish
  577.      * and save the command exit status. This is adapted from pclose.
  578.      */
  579. #ifdef sgi
  580.     while (((ret = waitpid(pid, &status, 0)) < 0) && oserror() == EINTR)
  581.     ;
  582. #else
  583.     while (((ret = waitpid(pid, &status, 0)) < 0) && errno == EINTR)
  584.     ;
  585. #endif
  586.     _SLspooler_exit = ((ret < 0) || (ready_ret == 0)) ?
  587.     SL_ERROR : WEXITSTATUS(status);
  588.  
  589.     /*
  590.      * Restore the original SIGCLD handler. If there are zombies
  591.      * out there a SIGCLD will be raised and the user's desired action
  592.      * will be performed.
  593.      */
  594.     (void)sigaction(SIGCLD, &orig_sact, NULL);
  595.  
  596.     /*
  597.      * If the command exit code was not 0 but we do not have any
  598.      * spooler error message, put some generic message in the output
  599.      * buffer so that apps get some sort of error text.
  600.      */
  601.     if (_SLspooler_exit != 0 && _SLspooler_nout == 0) {
  602.     spooler_buf_add(gettxt(_SGI_LIBSPOOL_SPOOLER_CMD_ERR_1,
  603.                 "Spooler command execution error."));
  604.     spooler_buf_add(gettxt(_SGI_LIBSPOOL_SPOOLER_CMD_ERR_2,
  605.                 "Filenames or other input data may"));
  606.     spooler_buf_add(gettxt(_SGI_LIBSPOOL_SPOOLER_CMD_ERR_3,
  607.                 "be improperly specified."));
  608.     }
  609.  
  610.     return _SLspooler_exit;
  611. }
  612.  
  613.  
  614. /*
  615.  ========================================================================
  616.             LOCAL FUNCTIONS
  617.  ========================================================================
  618. */
  619.  
  620.  
  621. /**************************************************************************
  622.  *
  623.  * Function: spooler_buf_init
  624.  *
  625.  * Description: Initializes the spooler output message buffer global
  626.  *    variables.
  627.  *
  628.  * Parameters: none
  629.  *
  630.  * Return: none
  631.  *
  632.  **************************************************************************/
  633.  
  634. static void spooler_buf_init(void)
  635. {
  636.     register int i;
  637.  
  638.     if (_SLspooler_nout) {
  639.     for (i = 0; i < _SLspooler_nout; i++)
  640.         free((char*)_SLspooler_out_buf[i]);
  641.     free((char*)_SLspooler_out_buf);
  642.     _SLspooler_out_buf = NULL;
  643.     _SLspooler_nout = 0;
  644.     }
  645.  
  646. }
  647.  
  648.  
  649. /**************************************************************************
  650.  *
  651.  * Function: spooler_buf_add
  652.  *
  653.  * Description: Adds the specified text line to the spooler output message
  654.  *    buffer.
  655.  *
  656.  * Parameters: 
  657.  *    str (I) - line of text to add to buffer
  658.  *
  659.  * Return: none
  660.  *
  661.  **************************************************************************/
  662.  
  663. static void spooler_buf_add(char *str)
  664. {
  665.     _SLspooler_nout++;
  666.     if (_SLspooler_out_buf)
  667.         _SLspooler_out_buf = (char**)realloc((char*)_SLspooler_out_buf,
  668.                     _SLspooler_nout * sizeof(char*));
  669.     else
  670.     _SLspooler_out_buf = (char**)malloc(sizeof(char*));
  671.     _SLspooler_out_buf[_SLspooler_nout-1] = strdup(str);
  672. }
  673.  
  674.  
  675. /**************************************************************************
  676.  *
  677.  * Function: read_ready
  678.  *
  679.  * Description: Does a select on the read end of the child process output
  680.  *    pipe. The select will timeout if there is some problem (e.g.
  681.  *    rsh hanging) or will return normally indicating we have output
  682.  *    ready to read.
  683.  *
  684.  * Parameters: 
  685.  *    read_fd (I) - fd to select on for read
  686.  *    do_select (I) - TRUE == do the timed select. FALSE == simply
  687.  *            return a ready indication.
  688.  *
  689.  * Return: 1 is returned if we are ready to read. 0 is returned if select
  690.  *    has timed out.
  691.  *
  692.  **************************************************************************/
  693.  
  694. static int read_ready(int read_fd, int do_select)
  695. {
  696.     fd_set fdset;
  697.     struct timeval timeout;
  698.     int ret, rv = 0, again = 1;
  699.  
  700.     /*
  701.      * Return immediately with a ready if select not requested
  702.      */
  703.     if (do_select == SL_FALSE)
  704.     return 1;
  705.  
  706.     /*
  707.      * Run select in a loop in case the call is interrupted by a
  708.      * signal (EINTR). This way we can reissue the select.
  709.      */
  710.     while (again) {
  711.     /*
  712.      * Clear the descriptor array and set our descriptor
  713.      * for select
  714.      */
  715.         FD_ZERO(&fdset);
  716.         FD_SET(read_fd, &fdset);
  717.  
  718.     /*
  719.      * Set a timeout. Note that we do this in the loop per
  720.      * select man page recommendation (see BUGS section in
  721.      * man page).
  722.      */
  723.         timeout.tv_sec = SLnet_timeout;
  724.         timeout.tv_usec = 0;
  725.  
  726.     /*
  727.      * Issue the select and handle the response. If a timeout
  728.      * occurs return with 0. If select returns normally, return
  729.      * a 1. If select is interrupted, don't return but do
  730.      * another select. If select returns with any other error
  731.      * call it a draw and return 0.
  732.      */
  733.         ret = select(read_fd + 1, &fdset, (fd_set*)NULL,
  734.                         (fd_set*)NULL, &timeout);
  735.     again = 0;
  736.     if (ret < 0 && errno == EINTR)
  737.         again = 1;
  738.     else if (ret > 0)
  739.         rv = 1;
  740.     }
  741.  
  742.     return rv;
  743. }
  744.